<template>
	<!-- 工具栏 -->
	<div class="tool-bar" v-show="totalPageNum != 0">
		<div class="pageNo">{{ currentPageNum }} / {{ totalPageNum }}页</div>
		<span class="txt">放大</span>
		<div class="box">
			<div class="mask" v-show="zoom == maxZoom"></div>
			<el-icon @click="zoomChange('plus')"><Plus /></el-icon>
		</div>
		<span class="txt">缩小</span>
		<div class="box">
			<div class="mask" v-show="zoom == minZoom"></div>
			<el-icon @click="zoomChange('minus')"><Minus /></el-icon>
		</div>
	</div>
	<!-- 工具栏 end -->
	<div class="pdf-viewer" @scroll="onScroll">
		<template v-for="item in totalPageNum" :key="item">
			<canvas class="pdf-item" :id="`pdf-canvas-${item}`" :style="{ zoom: zoom / 10 }" />
		</template>
	</div>
</template>

<script>
import { reactive, toRefs, nextTick, watchEffect } from 'vue'
import * as pdfjs from 'pdfjs-dist'
import pdfjsWorker from 'pdfjs-dist/build/pdf.worker.entry'
import { ElMessage } from 'element-plus'

pdfjs.GlobalWorkerOptions.workerSrc = pdfjsWorker

export default {
	name: 'PdfViewer',
	props: {
		url: { type: String, default: '' } // pdf文件路径
	},
	emits: ['onRendered'],
	setup(props, { emits }) {
		const state = reactive({
			pdfCtx: null,

			currentPageNum: 0, // 当前页
			totalPageNum: 0,
			zoom: 10, // 目前暂时采用css方式缩放页面
			minZoom: 10, // 缩放最小值 一倍
			maxZoom: 50 // 缩放最大值 五倍
		})

		const resolvePdf = url => {
			const loadingTask = pdfjs.getDocument(url)
			loadingTask.promise.then(pdf => {
				state.pdfCtx = pdf
				state.totalPageNum = pdf.numPages
				state.currentPageNum = 1

				// 动态计算scale
				pdf.getPage(1).then(res => {
					let boxWidth = document.body.clientWidth - 20
					const [x1, , x2] = res._pageInfo.view
					const pageWidth = x2 - x1
					state.scale = (boxWidth * (state.maxZoom / 10)) / pageWidth
				})
				nextTick(() => {
					renderPdf()
				})
			})
		}

		const renderPdf = (num = 1) => {
			state.pdfCtx.getPage(num).then(page => {
				const canvas = document.getElementById(`pdf-canvas-${num}`)
				const ctx = canvas.getContext('2d')
				const viewport = page.getViewport({ scale: state.scale })
				// 画布大小,默认值是width:300px,height:150px
				canvas.width = viewport.width
				canvas.height = viewport.height
				// 画布的dom大小, 设置移动端,宽度设置铺满整个屏幕
				const clientWidth = document.body.clientWidth - 20
				canvas.style.width = clientWidth + 'px'
				// 根据pdf每页的宽高比例设置canvas的高度
				canvas.style.height = clientWidth * (viewport.height / viewport.width) + 'px'
				page.render({
					canvasContext: ctx,
					viewport
				})
				if (num < state.totalPageNum) {
					renderPdf(num + 1)
				} else {
					emits('onRendered')
				}
			})
		}

		const zoomChange = value => {
			state.zoom = value == 'plus' ? state.zoom + 5 : state.zoom - 5

			let pdfViewer = document.getElementsByClassName('pdf-viewer')[0]
			let pages = document.getElementsByClassName('pdf-item')
			pdfViewer.scrollTop = (pages[state.currentPageNum - 1].offsetTop * state.zoom) / 10
		}

		const onScroll = e => {
			let pages = document.getElementsByClassName('pdf-item')
			for (let i = 0; i < state.totalPageNum; i++) {
				let offset = e.target.offsetHeight / 2 - 100 // 距顶部的距离(当前页在滚动到页面可视区的哪个位置时更改currentPageNum)
				if (e.target.scrollTop >= (pages[i].offsetTop * state.zoom) / 10 - offset) {
					if ((pages[i + 1] && e.target.scrollTop < (pages[i + 1].offsetTop * state.zoom) / 10 - offset) || !pages[i + 1]) {
						state.currentPageNum = i + 1
					}
				}
			}
		}

		watchEffect(() => {
			if (props.url) {
				ElMessage({
					showClose: true,
					message: '文件加载中...',
					type: 'success'
				})
				resolvePdf(props.url)
			}
		})
		return {
			...toRefs(state),
			zoomChange,
			onScroll
		}
	}
}
</script>

<style lang="scss" scoped>
.pdf-viewer {
	position: absolute;
	top: 0;
	right: 0;
	bottom: 0;
	left: 0;
	padding: 10px 10px 50px;
	overflow: scroll;
	background-color: #f5f5f5;
}

// 工具栏
.tool-bar {
	position: absolute;
	top: 0;
	right: 0;
	left: 0;
	z-index: 2;
	display: flex;
	justify-content: flex-end;
	height: 45px;
	padding: 0 20px;
	line-height: 45px;
	color: #ffffff;
	background-color: rgb(85 85 85 / 60%);
	.pageNo {
		flex: 1;
		font-size: 17px;
	}
	.txt {
		padding-right: 5px;
		margin-left: 20px;
		font-size: 16px;
	}
	.box {
		position: relative;
		width: 35px;
		height: 35px;
		margin-top: 5px;
		line-height: 35px;
		text-align: center;
		background-color: #3476fe;
		border-radius: 50%;
		.van-icon {
			font-weight: bold;
			vertical-align: middle;
		}
		.mask {
			position: absolute;
			top: 0;
			left: 0;
			z-index: 1;
			width: 100%;
			height: 100%;
			background-color: rgb(109 109 109 / 70%);
			border-radius: 50%;
		}
	}

	// 工具栏 end
}
</style>
